#ifndef TYPES_HH
#define TYPES_HH

#ifdef __OPENCL_VERSION__

#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics: enable

#ifdef USE_DOUBLE_PRECISION

#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#elif cl_amd_fp64
#pragma OPENCL EXTENSION cl_amd_fp64 : enable
#else
#error Not possible to enable double precision in this device!
#endif

typedef double real;
typedef double2 real2;
typedef double3 real3;
typedef double4 real4;
#define INFOP(message) printf("%sUSING DOUBLE PRECISION%s\n","\033[0;32m","\033[0m");
#else
typedef float real;
typedef float2 real2;
typedef float3 real3;
typedef float4 real4;
#define INFOP(message) printf("%sUSING SINGLE PRECISION%s\n","\033[0;32m","\033[0m");
#endif //USE__DOUBLE_PRESITION
#else
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#ifdef USE_DOUBLE_PRECISION
typedef double real;
typedef cl_double cl_real;
typedef cl_double2 cl_real2;
typedef cl_double3 cl_real3;
typedef cl_double4 cl_real4;
#define INFOP(message) printf("%sUSING DOUBLE PRECISION%s\n","\033[0;32m","\033[0m");
#else
typedef float real;
typedef cl_float cl_real;
typedef cl_float2 cl_real2;
typedef cl_float3 cl_real3;
typedef cl_float4 cl_real4;
#define INFOP(message) printf("%sUSING SINGLE PRECISION%s\n","\033[0;32m","\033[0m");
#endif  //USE_DOUBLE_PRECISION
#include <string>
//PARAMETERS KEYS
#define p_INPUT_FILE "PART_INPUT_FILE"                       //string
#define p_PART_OUT_NAME "PART_OUT_NAME_BASE"            //string
#define p_VTK_OUT_NAME "VTK_OUT_NAME_BASE"              //string

#define p_TIME_STEP "TIMESTEP_LENGTH"                        //real
#define p_END_TIME "TIME_END"                                //real
#define p_EPSILON "EPSILON"                                  //real
#define p_SIGMA "SIGMA"                                      //real
#define p_X_MIN "X_MIN"                                      //real
#define p_X_MAX "X_MAX"                                      //real
#define p_Y_MIN "Y_MIN"                                      //real
#define p_Y_MAX "Y_MAX"                                      //real
#define p_Z_MIN "Z_MIN"                                      //real
#define p_Z_MAX "Z_MAX"                                      //real
#define p_R_CUT "R_CUT"                                      //real
#define p_RHO_0 "RHO_0"                                      //real
#define p_K_GAS "K_GAS"                                    //real
#define p_VISCO "VISCOSITY"                                  //real
#define p_GX "G_X"
#define p_GY "G_Y"
#define p_GZ "G_Z"


#define p_PART_OUT_FREQ "PART_OUT_FREQ"                      //integer
#define p_VTK_OUT_FREQ "VTK_OUT_FREQ"                        //integer
#define p_CL_WORKGROUP_SIZE "CL_WORKGROUP_SIZE"              //integer
#define p_CLWORKGROUP_1DSIZE "CL_WORKGROUP_1DSIZE"            //integer
#define p_CLWORKGROUP_3DSIZE_X "CL_WORKGROUP_3DSIZE_X"        //integer
#define p_CLWORKGROUP_3DSIZE_Y "CL_WORKGROUP_3DSIZE_Y"        //integer
#define p_CLWORKGROUP_3DSIZE_Z "CL_WORKGROUP_3DSIZE_Z"        //integer
#define p_XN "X_N"                                           //integer
#define p_YN "Y_N"                                           //integer
#define p_ZN "Z_N"                                           //integer
#define p_REFLECTX "REFLECT_X"
#define p_REFLECTY "REFLECT_Y"
#define p_REFLECTZ "REFLECT_Z"

typedef enum {NOSLIP=1, SLIP=2, OUTFLOW=3, PERIODIC=4, NEUMANN=5 ,INFLOW=6} BCTYPE;
enum dimension {ONED=1,TWOD=2,THREED=3};

//PARAMETERS DEFAULT VALUES
const std::string v_INPUT_FILE = "def_file.txt";
const std::string v_PART_OUT_NAME = "def_part_out_n";
const std::string v_VTK_OUT_NAME = "def_vtk_out_n";

const real v_TIME_STEP=0.1;
const real v_END_TIME=1.0;
const real v_EPSILON=0.0;
const real v_SIGMA=1.00;
const real v_X_MIN=0.0;
const real v_X_MAX=1.0;
const real v_Y_MIN=0.0;
const real v_Y_MAX=1.0;
const real v_Z_MIN=0.0;
const real v_Z_MAX=1.0;
const real v_R_CUT=0.0;
const real v_RHO_0=0.0;
const real v_K_GAS=0.0;
const real v_VISCO=0.0;
const real v_GX=0.0;
const real v_GY=0.0;
const real v_GZ=0.0;

const int v_PART_OUT_FREQ=1;
const int v_VTK_OUT_FREQ=1;
const int v_CL_WORKGROUP_SIZE=128;
const int v_CLWORKGROUP_1DSIZE=128;
const int v_CLWORKGROUP_3DSIZE_X=128;
const int v_CLWORKGROUP_3DSIZE_Y=128;
const int v_CLWORKGROUP_3DSIZE_Z=128;
const int v_XN=1;
const int v_YN=1;
const int v_ZN=1;
const int v_REFLECTX=0;
const int v_REFLECTY=0;
const int v_REFLECTZ=0;

typedef enum {EAST=1, WEST=2, NORTH=3, SOUTH=4, FRONT=5 ,BACK=6} BCFACE;


#endif  //__OPENCL__VERSION__

#endif //TYPES_HH
